package cn.com.ursaminor.mysql4j.core;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import cn.com.ursaminor.mysql4j.util.Mysql4jUtil;

/*
  	Single-Table Syntax:
  
	UPDATE [LOW_PRIORITY] [IGNORE] table_reference
	    SET assignment_list
	    [WHERE where_condition]
	    [ORDER BY ...]
	    [LIMIT row_count]
	
	value:
	    {expr | DEFAULT}
	
	assignment:
	    col_name = value
	
	assignment_list:
	    assignment [, assignment] ... 
	    
	-------------------------------------------------------
	
	Multiple-Table Syntax:
	
	UPDATE [LOW_PRIORITY] [IGNORE] table_references
    	SET assignment_list
    	[WHERE where_condition]
 */
/**
 * 该类拼接生成update语句，并提交.
 * 
 * @author 小熊
 * @version 1.0
 */
public class Updater
{
	private final static Logger logger = Logger.getLogger(Updater.class);
	
	//------------------------------------------------------------------------------------------------------------------
	
	private Table table;
	
	private StringBuffer update;
	private StringBuffer set;
	private StringBuffer where;
	private StringBuffer order;
	private StringBuffer limit;
	
	/**
	 *	构造方法.
	 *
	 *	@param table 要更新数据的表
	 */
	public Updater(Table table)
	{
		this.table = table;
		update = new StringBuffer("update ").append(table.getString());
	}
	
	/**
	 *	关联表，用于关联方式更新数据.
	 *
	 *	@param abstTable 关联表
	 *  @return 当前Updater对象
	 */
	public Updater with(AbstTable abstTable)
	{
		update.append(",").append(abstTable.getString());
		return this;
	}
	
	/**
	 *	关联表，用于关联方式更新数据.
	 *
	 *	@param abstTable 关联表
	 *	@param expr 布尔表达式
	 *  @return 当前Updater对象
	 */
	public Updater with(AbstTable abstTable, BoolExpr expr)
	{
		with(abstTable);
		where(expr);
		return this;
	}
	
	/**
	 *	更新字段值.
	 *
	 *	@param column 字段
	 *	@param value 值
	 *  @return 当前Updater对象
	 */
	public Updater set(Chr column, String value)
	{
		String expr = column.getString() + "='" + value + "'";
		if(set==null) set = new StringBuffer(" set ").append(expr);
		else set.append(",").append(expr);
		return this;
	}
	
	/**
	 *	更新字段值.
	 *
	 *	@param column 字段
	 *	@param value 值
	 *  @return 当前Updater对象
	 */
	public Updater set(Num column, Number value)
	{
		String expr = column.getString() + "=" + value;
		if(set==null) set = new StringBuffer(" set ").append(expr);
		else set.append(",").append(expr);
		return this;
	}
	
	/**
	 *	更新字段值.
	 *
	 *	@param column 字段
	 *	@param value 值
	 *  @return 当前Updater对象
	 */
	public Updater set(Datetime column, Date value)
	{
		String expr = column.getString() + "='" + Mysql4jUtil.formatDate(value) + "'";
		if(set==null) set = new StringBuffer(" set ").append(expr);
		else set.append(",").append(expr);
		return this;
	}
	
	/**
	 *	用另一个字段更新字段值.
	 *
	 *	@param column 字段
	 *	@param value 值
	 *  @return 当前Updater对象
	 */
	public Updater set(Chr column, Chr value)
	{
		String expr = column.getString() + "=" + value;
		if(set==null) set = new StringBuffer(" set ").append(expr);
		else set.append(",").append(expr);
		return this;
	}
	
	/**
	 *	用另一个字段更新字段值.
	 *
	 *	@param column 字段
	 *	@param value 值
	 *  @return 当前Updater对象
	 */
	public Updater set(Num column, Num value)
	{
		String expr = column.getString() + "=" + value;
		if(set==null) set = new StringBuffer(" set ").append(expr);
		else set.append(",").append(expr);
		return this;
	}
	
	/**
	 *	用另一个字段更新字段值.
	 *
	 *	@param column 字段
	 *	@param value 值
	 *  @return 当前Updater对象
	 */
	public Updater set(Datetime column, Datetime value)
	{
		String expr = column.getString() + "=" + value;
		if(set==null) set = new StringBuffer(" set ").append(expr);
		else set.append(",").append(expr);
		return this;
	}
	
	/**
	 *	更新字段值.
	 *
	 *	@param column 字段
	 *	@param value 函数表达式
	 *  @return 当前Updater对象
	 */
	public Updater set(Column column, FunExpr value)
	{
		String expr = column.getString() + "=" + value;
		if(set==null) set = new StringBuffer(" set ").append(expr);
		else set.append(",").append(expr);
		return this;
	}
	
	/**
	 *	拼接where子句.
	 *
	 *	@param expr 布尔表达式
	 *  @return 当前Updater对象
	 *  @see Query#where(BoolExpr)
	 */
	public Updater where(BoolExpr expr)
	{
		if(expr==null || expr.getString()==null) return this;
		if(expr.getCount()>1)
		{
			if(where==null) where = new StringBuffer(" where (").append(expr.getString()).append(")");
			else where.append(" and (").append(expr.getString()).append(")");
		}
		else
		{
			if(where==null) where = new StringBuffer(" where ").append(expr.getString());
			else where.append(" and ").append(expr.getString());
		}
		return this;
	}
	
	/**
	 *	拼接order by子句.
	 *
	 *	@param o 字段数组
	 *  @return 当前Updater对象
	 *  @see Query#order(Column...)
	 */
	public Updater order(Column...o)
	{
		if(o==null) return this;
		for(Column oo : o)
		{
			if(oo==null) continue;
			if(order==null) order = new StringBuffer(" order by ").append(oo.getString());
			else order.append(",").append(oo.getString());
		}
		return this;
	}
	
	/**
	 *	拼接order by子句.
	 *
	 *	@param f 函数表达式数组
	 *  @return 当前Updater对象
	 *  @see Query#order(FunExpr...)
	 */
	public Updater order(FunExpr...f)
	{
		if(f==null) return this;
		for(FunExpr ff : f)
		{
			if(ff==null) continue;
			if(order==null) order = new StringBuffer(" order by ").append(ff.getString());
			else order.append(",").append(ff.getString());
		}
		return this;
	}
	
	/**
	 *	拼接limit子句.
	 *
	 *	@param offset 偏移量
	 *  @param count 返回结果数
	 *  @return 当前Updater对象
	 *  @see Query#limit(Integer, Integer)
	 */
	public Updater limit(Integer offset, Integer count)
	{
		limit = new StringBuffer(" limit ").append(offset).append(",").append(count);
		return this;
	}
	
	/**
	 *	拼接limit子句.
	 *
	 *  @param count 返回结果数
	 *  @return 当前Updater对象
	 *  @see Query#limit(Integer)
	 */
	public Updater limit(Integer count)
	{
		limit = new StringBuffer(" limit ").append(count);
		return this;
	}
	
	/**
	 *	获得当前sql语句.
	 *
	 *  @return sql语句 
	 */
	public String getSql()
	{
		return new StringBuffer(update).append(set).append(where==null?"":where).append(order==null?"":order).append(limit==null?"":limit).toString();
	}
	
	/**
	 *	提交sql.
	 *
	 *  @return 影响行数
	 */
	public int execute()
	{
		String sql = getSql();
		logger.info(sql);
		int r = table.getJdbcTemplate().update(sql);
		return r;
	}
	
	public String toString()
    {
    	return getSql();
    }
	
	// --静态快捷方法-----------------------------------------------------------------------------------------------------
	
	/**
	 *	获得更新pojo对象的sql语句.
	 *
	 *	@param table 表
	 *	@param pojo pojo对象，也可为Row对象
	 *  @return sql语句 
	 */
	public static String getSql(Table table, Object pojo)
	{
		StringBuffer set = null;
		for(int i=0; i<table.columns.size(); i++)
		{
			Column c = table.columns.get(i);
			
			if(c.pk) continue;
			try
			{
				Object obj = null;
				if(Map.class.isAssignableFrom(pojo.getClass()))
				{
					obj = ((Map)pojo).get(c.getAliasOrName());
				}
				else
				{
					Method method = c.method;
					if(method!=null) obj = method.invoke(pojo, new Object[0]);
				}
				if(set==null)
				{
					if(c instanceof Chr) set = new StringBuffer(" set " + c.name + "=" + (obj==null?"null":("'"+obj+"'")));
					else if(c instanceof Num) set = new StringBuffer(" set " + c.name + "=" + (obj==null?"null":obj.toString()));
					else if(c instanceof Datetime) set = new StringBuffer(" set " + c.name + "=" + (obj==null?"null":("'"+Mysql4jUtil.formatDate((Date)obj)+"'")));
				}
				else
				{
					if(c instanceof Chr) set.append(",").append(c.name).append("=").append(obj==null?"null":("'"+obj+"'"));
					else if(c instanceof Num) set.append(",").append(c.name).append("=").append(obj==null?"null":obj.toString());
					else if(c instanceof Datetime) set.append(",").append(c.name).append("=").append(obj==null?"null":("'"+Mysql4jUtil.formatDate((Date)obj)+"'"));
				}
			}
			catch(Exception e)
			{
				logger.error(e);
			}
		}
		
		try
		{
			Column pk = table.primaryKey;
			Object obj = null;
			
			if(pojo instanceof Map)
        	{
        		obj = ((Map)pojo).get(pk.getAliasOrName());
        		if(obj==null) throw new Exception("The value of primaryKey " + pk.getAliasOrName() + " is null!");
        	}
			else
			{
				Method method = pk.method;
				if(method==null) throw new Exception("The getter method of primaryKey is not exist!");
				obj = method.invoke(pojo, new Object[0]);
				if(obj==null) throw new Exception("The value of primaryKey "+method.getName()+"() returned null!");
			}
			
			String value = null;
			if(pk instanceof Num) value = obj.toString();
			else if(pk instanceof Chr) value = "'"+obj+"'";
			else if(pk instanceof Datetime) value = "'"+Mysql4jUtil.formatDate((Date)obj)+"'";
			
			return new StringBuffer("update ").append(table.getClass().getSimpleName()).append(set).append(" where ").append(pk.name).append("=").append(value).toString();
		}
		catch(Exception e)
		{
			logger.error(e);
			return null;
		}
	}
	
	/**
	 *	把pojo数据更新到table表中，空值会覆盖原有值.
	 *
	 *	@param table 表
	 *  @param pojo 数据对象
	 *  @return 影响行数
	 */
	public static int update(Table table, Object pojo)
	{
		String sql = getSql(table,pojo);
		logger.info(sql);
		return table.getJdbcTemplate().update(sql);
	}
	
	/**
	 *	把pojo数据列表更新到table表中，更新多条记录，空值会覆盖原有值.
	 *
	 *	@param table 表
	 *  @param pojos 数据对象列表
	 *  @return 影响行数
	 */
	public static int update(Table table, List pojos)
	{
		if(pojos==null || pojos.size()==0) return 0;
		
		int result = 0;
		for(Object pojo : pojos)
		{
			result += update(table, pojo);
		}
		return result;
	}
}
